home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / compression / xpk / xpkdisk3.lha / device2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-08  |  12.2 KB  |  513 lines

  1. /*-
  2.  * DEVICE2.C
  3.  *
  4.  * The xpkdisk.device code that makes it a real Exec .device.
  5.  * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  6.  *
  7.  * $Id: device2.c,v 1.3 1993/11/08 13:11:15 Rhialto Rel $
  8.  * $Log: device2.c,v $
  9.  * Revision 1.3  1993/11/08  13:11:15  Rhialto
  10.  * Add RCS tags.
  11.  *
  12.  *
  13.  * This code is (C) Copyright 1989-1993 by Olaf Seibert. All rights reserved.
  14.  * May not be used or copied without a licence.
  15. -*/
  16.  
  17. #include "xpkdisk.h"
  18. #include <exec/initializers.h>
  19.  
  20. /*#undef DEBUG            */
  21. #ifdef DEBUG
  22. #   include "syslog.h"
  23. #else
  24. #   define    debug(x)
  25. #endif
  26. /* INDENT ON */
  27.  
  28. Prototype __geta4 DEV *Init(__A0 long segment, __D0 struct XpkDiskDevice *dev, __A6 struct ExecBase *execbase);
  29. Prototype __geta4 void DevOpen(__D0 ulong unitno, __D1 ulong flags, __A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  30. Prototype __geta4 long DevClose(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  31. Prototype __geta4 long DevExpunge(__A6 DEV *dev);
  32. Prototype __geta4 void DevBeginIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  33. Prototype __geta4 long DevAbortIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  34.  
  35. Prototype void TermIO(struct IOStdReq *ioreq);
  36. Prototype void WakePort(struct MsgPort *port);
  37. Prototype __geta4 void UnitTask(void);
  38. Prototype void CMD_Invalid(struct IOStdReq *ioreq, UNIT *unit);
  39. Prototype void CMD_Stop(struct IOStdReq *ioreq, UNIT *unit);
  40. Prototype void CMD_Start(struct IOStdReq *ioreq, UNIT *unit);
  41. Prototype void CMD_Flush(struct IOStdReq *ioreq, UNIT *unit);
  42.  
  43. Prototype const char DevName[];
  44. Prototype const char idString[];
  45.  
  46. const char    DevName[] = "xpkdisk.device";
  47. const char    idString[] = "$VER: xpkdisk.device $Revision: 1.3 $\r\n";
  48.  
  49. /*
  50.  * Device commands:
  51.  */
  52.  
  53. const void    (*funcTable[]) (struct IOStdReq *, UNIT *) = {
  54.     CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  55.     CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  56.     TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  57.     TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  58.     TD_Remchangeint, TD_Getgeometry, TD_Eject,
  59. };
  60.  
  61. #define LAST_TD_COMM        TD_EJECT
  62.  
  63. long        SysBase;    /* Argh! A global variable! */
  64.  
  65. /*
  66.  * The Initialization routine is given a seglist pointer, the device
  67.  * base pointer, and the Exec base pointer. We are being called from
  68.  * InitResident. Exec has Forbid() for us during the call.
  69.  */
  70.  
  71.  
  72. __geta4 DEV    *
  73. Init(segment, dev, execbase)
  74. __A0 long    segment;
  75. __D0 DEV       *dev;
  76. __A6 struct ExecBase *execbase;
  77. {
  78.     SysBase = *(long *) 4;
  79. #ifdef DEBUG
  80.     initsyslog();
  81.     debug(("seg %lx, dev %lx, sys %lx\n", segment, dev, execbase));
  82. #endif
  83.     if (DevInit(dev)) {
  84.     dev->xd_Seglist = segment;
  85.     debug(("Init done.\n"));
  86.     return dev;
  87.     }
  88.     FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  89.     return NULL;
  90. }
  91.  
  92. /*
  93.  * Open is given the device pointer, unitno and flags.    Either return the
  94.  * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  95.  * Forbid() for us during the call.
  96.  */
  97.  
  98. __geta4 void
  99. DevOpen(unitno, flags, ioreq, dev)
  100. __D0 ulong    unitno;
  101. __D1 ulong    flags;
  102. __A1 struct IOStdReq *ioreq;
  103. __A6 DEV       *dev;
  104. {
  105.     UNIT       *unit;
  106.  
  107.     debug(("OpenDevice %lx unit %ld, flags %lx\n", dev, unitno, flags));
  108.     ++dev->dev_OpenCnt;
  109.     if (unitno >= XD_NUMUNITS)
  110.     goto error;
  111.  
  112.     if ((unit = dev->xd_Unit[unitno]) == NULL) {
  113.     debug(("Call UnitInit\n"));
  114.     if ((unit = UnitInit(dev, unitno)) == NULL)
  115.         goto error;
  116.     debug(("UnitInit succeeded: %x\n", unit));
  117.     dev->xd_Unit[unitno] = unit;
  118.     }
  119.     ioreq->io_Unit = (struct Unit *) unit;
  120.  
  121.     ++unit->xu_OpenCnt;
  122.     dev->dev_Flags &= ~LIBF_DELEXP;
  123.     ioreq->io_Error = 0;
  124.  
  125.     debug(("DevOpen: success\n"));
  126.     return;
  127.  
  128. error:
  129.     --dev->dev_OpenCnt;
  130.     ioreq->io_Error = IOERR_OPENFAIL;
  131.     debug(("DevOpen: fail\n"));
  132. }
  133.  
  134. /*
  135.  * Close is given the device pointer and the io request.  Be sure not to
  136.  * decrement the open count if already zero.    If the open count is or
  137.  * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  138.  * return the seglist.    Otherwise we return NULL.
  139.  *
  140.  * Note that this routine never sets LIBF_DELEXP on its own.
  141.  *
  142.  * Exec has Forbid() for us during the call.
  143.  */
  144.  
  145. __geta4 long
  146. DevClose(ioreq, dev)
  147. __A1 struct IOStdReq *ioreq;
  148. __A6 DEV       *dev;
  149. {
  150.     UNIT       *unit;
  151.  
  152.     unit = (UNIT *) ioreq->io_Unit;
  153.     debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  154.  
  155.     /*
  156.      * See if the unit is still in use. If not, close it down.
  157.      */
  158.  
  159.     if (unit->xu_OpenCnt && --unit->xu_OpenCnt == 0) {
  160.     dev->xd_Unit[unit->xu_UnitNr] = NULL;
  161.     UnitCloseDown(ioreq, dev, unit);
  162.     }
  163.     /*
  164.      * Make sure the ioreq is not used again.
  165.      */
  166.     ioreq->io_Unit = (void *) -1;
  167.     ioreq->io_Device = (void *) -1;
  168.  
  169.     if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  170.     return NULL;
  171.     if (dev->dev_Flags & LIBF_DELEXP)
  172.     return DevExpunge(dev);
  173.     return NULL;
  174. }
  175.  
  176. /*
  177.  * We expunge the device and return the Seglist ONLY if the open count is
  178.  * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  179.  * flag and return NULL.
  180.  *
  181.  * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  182.  * called from the memory allocator and thus we CANNOT DO A Wait() or
  183.  * otherwise take a long time to complete (straight from RKM).
  184.  *
  185.  * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  186.  * freeze if we called it ourselves.  As far as I can tell from RKM,
  187.  * DevExpunge(lib) must remove the device itself as shown below.
  188.  */
  189.  
  190. __geta4 long
  191. DevExpunge(dev)
  192. __A6 DEV       *dev;
  193. {
  194.     long        Seglist;
  195.  
  196.     if (dev->dev_OpenCnt) {
  197.     dev->dev_Flags |= LIBF_DELEXP;
  198.     return NULL;
  199.     }
  200.     Remove(&dev->dev_Node);
  201.     DevCloseDown(dev);          /* Should be quick! */
  202. #ifdef DEBUG
  203.     uninitsyslog();
  204. #endif
  205.     Seglist = dev->xd_Seglist;
  206.     FreeMem((char *) dev - dev->dev_NegSize,
  207.         (long) dev->dev_NegSize + dev->dev_PosSize);
  208.     return Seglist;
  209. }
  210.  
  211. /*
  212.  * BeginIO entry point. We don't handle any QUICK requests, we just send
  213.  * the request to the proper unit to handle.
  214.  */
  215.  
  216. __geta4 void
  217. DevBeginIO(ioreq, dev)
  218. __A1 struct IOStdReq *ioreq;
  219. __A6 DEV       *dev;
  220. {
  221.     UNIT       *unit;
  222.  
  223.     /*
  224.      * Bookkeeping.
  225.      */
  226.     unit = (UNIT *) ioreq->io_Unit;
  227.     debug(("BeginIO: %x io %08lx dev %08lx u %08lx\n", ioreq->io_Command,
  228.         ioreq, dev, unit));
  229.  
  230.     /*
  231.      * See if the io command is within range.
  232.      */
  233.     if (STRIP(ioreq->io_Command) > LAST_TD_COMM)
  234.     goto NoCmd;
  235.  
  236. #ifdef HANDLE_IO_QUICK
  237.     Forbid();                   /* Disable(); is a bit too strong for us. */
  238. #endif
  239.  
  240.     /*
  241.      * Process all immediate commands no matter what. Don't even require
  242.      * an exclusive lock on the unit.
  243.      */
  244.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  245.     goto Immediate;
  246.  
  247.     /*
  248.      * We don't handle any QUICK I/O since that only gives trouble with
  249.      * message ports and so. Other devices normally would include the code
  250.      * below.
  251.      */
  252. #ifdef HANDLE_IO_QUICK
  253.     /*
  254.      * See if the user does not request QUICK IO. If not, it is likely to
  255.      * be async and therefore we don't do it sync.
  256.      */
  257.     if (!(ioreq->io_Flags & IOF_QUICK))
  258.     goto NoQuickRequested;
  259.  
  260.     /*
  261.      * See if the unit is STOPPED. If so, queue the msg.
  262.      */
  263.     if (unit->xu_Flags & UNITF_STOPPED)
  264.     goto QueueMsg;
  265.  
  266.     /*
  267.      * This is not an immediate command. See if the device is busy. If
  268.      * not, process the action in this (the caller's) context.
  269.      */
  270.     if (!BSET_ACTIVE(&unit->xu_Flags))
  271.     goto Immediate;
  272. #endif
  273.  
  274.     /*
  275.      * We need to queue the device. Clear the QUICK flag.
  276.      */
  277. QueueMsg:
  278.     ioreq->io_Flags &= ~IOF_QUICK;
  279. NoQuickRequested:
  280. #ifdef HANDLE_IO_QUICK
  281.     Permit();                   /* Enable(); is a bit too strong for us. */
  282. #endif
  283.     PutMsg(&unit->xu_Port, &ioreq->io_Message);
  284.  
  285.     return;
  286.  
  287. Immediate:
  288. #ifdef HANDLE_IO_QUICK
  289.     Permit();                   /* Enable(); is a bit too strong for us. */
  290. #endif
  291.     debug(("BeginIO: Immediate\n"));
  292.     ioreq->io_Error = TDERR_NoError;
  293.     PerformIO(ioreq, unit);
  294.     return;
  295.  
  296. NoCmd:
  297.     ioreq->io_Error = IOERR_NOCMD;
  298.     TermIO(ioreq);
  299.     return;
  300.  
  301. }
  302.  
  303. /*
  304.  * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  305.  * commands that don't call TermIO, or call it multiple times, may not be
  306.  * properly handled unless you are careful. TD_ADDCHANGEINT and
  307.  * TD_REMCHANGEINT are obvious examples.
  308.  */
  309.  
  310. void
  311. TermIO(ioreq)
  312. register struct IOStdReq *ioreq;
  313. {
  314.     register UNIT  *unit;
  315.  
  316.     unit = (UNIT *) ioreq->io_Unit;
  317.     debug(("TermIO: io %08lx u %08lx %ld %ld\n", ioreq, unit,
  318.        ioreq->io_Actual, (long)ioreq->io_Error));
  319.  
  320. #ifdef HANDLE_IO_QUICK
  321.     /*
  322.      * Since immediate commands don't even require an exclusive lock on
  323.      * the unit, don't unlock it.
  324.      */
  325.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  326.     goto Immediate;
  327.  
  328.     /*
  329.      * We may need to turn the active (lock) bit off, but not if we are
  330.      * within the task.
  331.      */
  332.     if (unit->xu_Flags & UNITF_INTASK)
  333.     goto Immediate;
  334.  
  335.     unit->xu_Flags &= ~UNITF_ACTIVE;
  336.  
  337.     /*
  338.      * The task may have work to do that came in while we were processing
  339.      * in the caller's context.
  340.      */
  341.     if (unit->xu_Flags & UNITF_WAKETASK) {
  342.     unit->xu_Flags &= ~UNITF_WAKETASK;
  343.     WakePort(&unit->xu_Port);
  344.     }
  345. #endif
  346.  
  347. Immediate:
  348.     /*
  349.      * If the quick bit is still set then wen don't need to reply the msg
  350.      * -- just return to the user.
  351.      */
  352.  
  353.     if (!(ioreq->io_Flags & IOF_QUICK))
  354.     ReplyMsg(&ioreq->io_Message);
  355.  
  356.     return;
  357. }
  358.  
  359. /*
  360.  * AbortIO entry point. We try to abort IO here.
  361.  */
  362.  
  363. __geta4 long
  364. DevAbortIO(ioreq, dev)
  365. __A1 struct IOStdReq *ioreq;
  366. __A6 DEV       *dev;
  367. {
  368.     Forbid();
  369.     if (ioreq->io_Flags & IOF_QUICK ||
  370.     IMMEDIATE & (1L << STRIP(ioreq->io_Command))) {
  371.     Permit();
  372.     return 1;
  373.     } else {
  374.     Remove(&ioreq->io_Message.mn_Node);
  375.     Permit();
  376.     ioreq->io_Error = IOERR_ABORTED;
  377.     ReplyMsg(&ioreq->io_Message);
  378.  
  379.     return 0;
  380.     }
  381. }
  382.  
  383. void
  384. WakePort(port)
  385. register struct MsgPort *port;
  386. {
  387.     Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  388. }
  389.  
  390. /*
  391.  * This is the main loop of the Unit tasks. It must be very careful with
  392.  * global data.
  393.  */
  394.  
  395. __geta4 void
  396. UnitTask(void)
  397. {
  398.     UNIT       *unit;
  399.     long        waitmask;
  400.     struct IOExtTD *ioreq;
  401.  
  402.     debug(("Start UnitTask\n"));
  403.     {
  404.     struct Task    *task;
  405.  
  406.     task = FindTask(NULL);
  407.     unit = (UNIT *) task->tc_UserData;
  408.     /* dev = unit->xu_Dev; */
  409.     task->tc_UserData = NULL;
  410.     debug(("task %lx unit %lx\n", task, unit));
  411.     }
  412.  
  413.     /*
  414.      * Now finish initializing the message ports and other signal things
  415.      */
  416.  
  417.     waitmask = UnitInit2(unit);
  418.     WakePort(&unit->xu_Port);
  419.  
  420.     for (;;) {
  421.     debug(("Task: Waiting...\n"));
  422.     Wait(waitmask);
  423.  
  424.     PollTimer(unit);
  425.  
  426.     /*
  427.      * See if we are stopped.
  428.      */
  429.     if (unit->xu_Flags & UNITF_STOPPED)
  430.         continue;
  431.  
  432. #ifdef HANDLE_IO_QUICK
  433.     /*
  434.      * Lock the device. If it fails, we have set a flag such that the
  435.      * TermIO wakes us again.
  436.      */
  437.     unit->xu_Flags |= UNITF_WAKETASK;
  438.     if (BSET_ACTIVE(&unit->xu_Flags))
  439.         continue;
  440.  
  441.     unit->xu_Flags |= UNITF_INTASK;
  442. #endif
  443.  
  444.     while (ioreq = (struct IOExtTD *) GetMsg(&unit->xu_Port)) {
  445.         debug(("Task: io %08lx %lx\n", ioreq, (long)ioreq->iotd_Req.io_Command));
  446.         ioreq->iotd_Req.io_Error = 0;
  447.         if (ioreq->iotd_Req.io_Command == CMD_Die)
  448.         goto die;
  449.         PerformIO((&ioreq->iotd_Req), unit);
  450.     }
  451.  
  452. #ifdef HANDLE_IO_QUICK
  453.     unit->xu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  454. #endif
  455.     }
  456.  
  457. die:
  458.     debug(("Aaargh! They stabbed me!\n"));
  459.     UnitCloseDown2(unit);
  460.     debug(("I'm gonna dieeeeeeeeeeee___________ .......\n"));
  461.     Forbid();
  462.     ioreq->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  463.     Signal((struct Task *)ioreq->iotd_Req.io_Message.mn_ReplyPort, SIGF_SINGLE);
  464.     /* fall off the end of the world */
  465. }
  466.  
  467. void
  468. CMD_Invalid(ioreq, unit)
  469. struct IOStdReq *ioreq;
  470. UNIT           *unit;
  471. {
  472.     ioreq->io_Error = IOERR_NOCMD;
  473.     TermIO(ioreq);
  474. }
  475.  
  476. void
  477. CMD_Stop(ioreq, unit)
  478. struct IOStdReq *ioreq;
  479. UNIT           *unit;
  480. {
  481.     unit->xu_Flags |= UNITF_STOPPED;
  482.     TermIO(ioreq);
  483. }
  484.  
  485. void
  486. CMD_Start(ioreq, unit)
  487. struct IOStdReq *ioreq;
  488. UNIT           *unit;
  489. {
  490.     unit->xu_Flags &= ~UNITF_STOPPED;
  491.     WakePort(&unit->xu_Port);
  492.     TermIO(ioreq);
  493. }
  494.  
  495. void
  496. CMD_Flush(ioreq, unit)
  497. struct IOStdReq *ioreq;
  498. UNIT           *unit;
  499. {
  500.     register struct IOStdReq *req;
  501.  
  502.     /* Flush our own command queue */
  503.     Forbid();
  504.     while (req = (struct IOStdReq *) GetMsg(&unit->xu_Port)) {
  505.     req->io_Error = IOERR_ABORTED;
  506.     ReplyMsg(&req->io_Message);
  507.     }
  508.     Permit();
  509.  
  510.     WakePort(&unit->xu_Port);
  511.     TermIO(ioreq);
  512. }
  513.